#pragma once
#include <sys/epoll.h>
#include "Log.hpp"

namespace wxd
{
    class Epoller
    {
    private:
        int Control(int flag, int fd, epoll_event *events)
        {
            return epoll_ctl(_epoll_fd, flag, fd, events);
        }

    public:
        Epoller()
            : _epoll_fd(-1)
        {
            // 创建epoll模型
            _epoll_fd = epoll_create(256);
            if (_epoll_fd < 0)
            {
                LOG(LogLevel::ERROR) << "epoll_create error!";
            }
            LOG(LogLevel::INFO) << "epoll_create success!";
        }

        int Add(int fd, uint32_t events)
        {
            struct epoll_event ep_event;
            ep_event.data.fd = fd;
            ep_event.events = events;
            int ret = Control(EPOLL_CTL_ADD, fd, &ep_event);
            if (ret < 0)
            {
                LOG(LogLevel::ERROR) << "Epoller Add Error!";
                return -1;
            }
            LOG(LogLevel::INFO) << "Epoller Add Success! fd = " << fd;
            return fd;
        }

        int Del(int fd)
        {        
            int ret = Control(EPOLL_CTL_DEL, fd,nullptr);
            if (ret < 0)
            {
                LOG(LogLevel::ERROR) << "Epoller Del Error!";
                return -1;
            }
            LOG(LogLevel::INFO) << "Epoller Del Success! fd = " << fd;
            return fd;
        }

        int Mod(int fd, bool enable_read,bool enable_write,bool enable_except)
        {
            struct epoll_event ep_event;
            ep_event.data.fd = fd;
            ep_event.events = (enable_read == true?EPOLLIN:0)|(enable_write == true?EPOLLOUT:0)|
            (enable_except == true?(EPOLLIN|EPOLLHUP):0);
            int ret = Control(EPOLL_CTL_MOD, fd, &ep_event);
            if (ret < 0)
            {
                LOG(LogLevel::ERROR) << "Epoller Mod Error!";
                return -1;
            }
            LOG(LogLevel::INFO) << "Epoller Mod Success! fd = " << fd;
            return fd;
        }

        int Wait(epoll_event *ep_event, int max_events_num, int timeout)
        {        
            int num = epoll_wait(_epoll_fd, ep_event, max_events_num, timeout);
            if(num < 0)
            {
                LOG(LogLevel::ERROR)<< "epoll_wait error!";
            }                
            return num;
        }

    private:
        int _epoll_fd;
    };

}